package educrypt.analysis;

import java.util.LinkedHashMap;
import java.util.Map;

import educrypt.commons.Alphabet;
import educrypt.commons.Text;

public class FrequencyAnalysis {

	private Text text;
	private Alphabet alphabet;
	private int ngramSize;
	private Frequencies frequencies;

	public FrequencyAnalysis(Text text, Alphabet alphabet, int ngramSize) {
		this.text = text;
		this.alphabet = alphabet;
		this.ngramSize = ngramSize;
		this.frequencies = analyze(ngramSize);
	}

	public Frequencies getFrequencies() {
		return frequencies;
	}

	public Text getText() {
		return text;
	}

	public Alphabet getAlphabet() {
		return alphabet;
	}

	public int getNgramSize() {
		return ngramSize;
	}

	// This method is used when we obtain the analysis from the DB
	public void setFrequencies(Frequencies frequencies) {
		this.frequencies = frequencies;
	}

	private Frequencies analyze(int ngramSize) {
		AnalysisNgrams textAsNgrams = text.toNgramCollection(ngramSize,
				alphabet);
		AnalysisNgrams symbols = alphabet.generatePermutations(ngramSize);

		// It is easier to calculate frequencies using Maps
		Map<String, Double> absoluteFrequency = this
				.calculateAbsoluteFrequency(textAsNgrams, symbols);
		Map<String, Double> percentages = this.calculatePercentage(
				textAsNgrams, absoluteFrequency);

		// Frequencies result object
		int size = percentages.size();
		Frequencies frequencies = new Frequencies(percentages.keySet().toArray(
				new String[size]), percentages.values().toArray(
				new Double[size]), absoluteFrequency.values().toArray(
				new Double[size]));

		return frequencies;
	}

	private Map<String, Double> calculateAbsoluteFrequency(AnalysisNgrams data,
			AnalysisNgrams symbols) {
		Map<String, Double> absoluteFrequency = this.initialize(symbols);
		Double freqAux = 0.0;
		for (String symbol : data) {
			freqAux = absoluteFrequency.get(symbol);
			if (freqAux == null) {
				// BREAKPOINT
				System.out.println("null");
			}
			absoluteFrequency.put(symbol, freqAux + 1);
		}
		return absoluteFrequency;
	}

	private Map<String, Double> initialize(AnalysisNgrams symbols) {
		Map<String, Double> initializedFrequencies = new LinkedHashMap<String, Double>(
				symbols.size(), 1);
		for (String symbol : symbols) {
			initializedFrequencies.put(symbol, 0.0);
		}
		return initializedFrequencies;
	}

	private Map<String, Double> calculatePercentage(AnalysisNgrams data,
			Map<String, Double> absoluteFrequency) {
		Map<String, Double> percentages = new LinkedHashMap<String, Double>(
				absoluteFrequency.size(), 1);
		int total = data.size();
		for (Map.Entry<String, Double> pair : absoluteFrequency.entrySet()) {
			double symbolPercentage = (pair.getValue() / total) * 100;
			percentages.put(pair.getKey(), symbolPercentage);
		}
		return percentages;
	}
}
